Vibe Code and Deploy a Web Search AI Agent

Last updated: January 26 2026

Overview

In this tutorial, you'll build a complete Web Search AI Agent β€” a full-stack application with a Python FastAPI backend and React frontend that can search the web and provide intelligent answers to your questions. The agent uses an LLM to decide when web search is needed, extracts search queries, fetches real-time results via BrightData's SERP API, and synthesizes comprehensive answers using the RAG (Retrieval-Augmented Generation) pattern.

The application includes a user-controlled "Web Search" checkbox that lets you toggle between:

  • Enabled: Agent searches the web using BrightData and synthesizes information
  • Disabled: Agent relies only on the LLM model's knowledge without web search
with-or-without-web-search
text
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        USER INTERFACE (React)                        β”‚
β”‚                    "What are the latest AI news?"                    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                   β”‚
                                   β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                      PYTHON BACKEND (FastAPI)                        β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚   Agent     │────▢│    LLM      │────▢│   Web Scraper       β”‚   β”‚
β”‚  β”‚ (Orchestrator)β”‚    β”‚  (Brain)    β”‚     β”‚ (BrightData SERP)   β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Prerequisites

Before starting, ensure you have:

  • Python 3.10+ installed
  • Node.js 18+ installed
  • API Keys (will be provided at the workshop or get your own):

AI Coding IDEs

Choose your favorite AI-powered coding assistant. Such as Cursor, Claude Code, Open AI Codex, Windsurf, Replit, JetBrains AI Assistant, GitHub Copilot, Tabnine, Sourcegraph Cody, Amazon Q Developer, Aider, Cline, Qoder, CodeGeeX etc.

Workshop Setup

Step 1: Create Your Workspace

Open your terminal and create a new empty folder:

bash
mkdir deep-research-agent

Step 2: Open the Folder in Your AI IDE

  • Cursor: File β†’ Open Folder
  • VS Code + Copilot: File β†’ Open Folder
  • Windsurf: File β†’ Open Folder

Step 3: Open the AI Chat Interface

  • Cursor: Press Cmd+K (Mac) or Ctrl+K (Windows) for inline, or Cmd+L / Ctrl+L for chat
  • GitHub Copilot: Click the Copilot icon or press Cmd+I / Ctrl+I
  • Windsurf: Press Cmd+L / Ctrl+L for Cascade

Vibe Coding Prompts

Follow these prompts in order. Copy each prompt into your AI coding assistant and let it generate the code!

> Note: These prompts include important technical details and fixes that ensure your implementation works correctly on the first try. The prompts may seem detailed, but this ensures you won't encounter common errors during development.

Prompt 1: Project Setup

> Goal: Set up the project structure

text
I want to build a deep research AI agent that can answer questions by searching the web when needed.

The backend will be Python and the frontend will be React. Set up a clean project structure with:
- A services folder containing backend and frontend directories
- A Makefile for running common commands

Just create the folder structure for now.
Expected Output:
  • services/backend/ folder created
  • services/frontend/ folder created
  • Empty Makefile created

Prompt 2: Backend Setup

> Goal: Initialize the Python backend

text
Set up the Python backend in services/backend/.

I'll need:
- FastAPI for the web server
- An async HTTP client for making API calls
- Environment variable support
- Data validation

Create the requirements.txt with the necessary dependencies.
Expected Output:

A requirements.txt file with FastAPI, uvicorn, httpx, python-dotenv, and pydantic.

Prompt 3: Environment Configuration

> Goal: Set up environment variables

text
I need to store API keys for two services:
1. Zeabur AI Hub - an OpenAI-compatible LLM API (token: ZEABUR_API_TOKEN)
2. BrightData - a web scraping service (token: BRIGHTDATA_API_TOKEN)

Create a .env.example template and a .env file in the backend folder. Also include a ZEABUR_MODEL variable defaulting to gpt-4o-mini.

Also create a config.py file that uses pydantic-settings to load these environment variables.
IMPORTANT: For the CORS_ORIGINS field, use Union[List[str], str] type and add a @field_validator to parse comma-separated strings from .env into a list. This prevents parsing errors.
Expected Output:
  • .env.example file with placeholder values
  • .env file ready to be filled in
  • config.py with Settings class and CORS validator

Prompt 4: LLM Client

> Goal: Create a client to talk to the LLM

text
I need to communicate with Zeabur AI Hub, which is an OpenAI-compatible API.

Create a Python client in services/backend/llm.py that can:
- Send prompts and get responses
- Support conversation history (chat)
- Handle errors gracefully

The base URL is https://sfo1.aihub.zeabur.ai and it uses the standard OpenAI chat completions format. Use async/await for the HTTP calls.
Expected Output:

A llm.py file with a class that can generate text and have conversations with the LLM.

> Goal: Create a web search capability using BrightData

text
I want to search the web using BrightData's SERP API.

Create a Python client in services/backend/scraper.py that:
- Takes a search query and returns Google search results
- Uses BrightData's API at https://api.brightdata.com/request
- Returns the parsed search results as JSON
- Handles errors without crashing

The API uses Bearer token authentication and needs these parameters:
- zone: "serp_api1"
- format: "json"
- data_format: "parsed_light"

IMPORTANT fixes to include:
1. Import and use urllib.parse.quote_plus to URL-encode the search query before building the Google search URL
2. Do NOT include a "language" parameter (BrightData rejects it)
3. BrightData returns response with structure {status_code, headers, body}. In _parse_search_results:
   - Check if data has a 'body' field and extract it
   - If body is a JSON string, parse it with json.loads()
   - Then look for 'organic' or 'organic_results' field for the search results
Expected Output:

A scraper.py file with a class that can search the web and return results.

Prompt 6: AI Agent

> Goal: Build the intelligent agent that decides when to search

text
Now I need to build the AI agent that ties everything together.

Create services/backend/agent.py with an agent that:
1. Receives a user question
2. Uses the LLM to decide: "Does this need current information from the web?"
3. If yes: extracts search keywords, searches the web, then answers based on results
4. If no: answers directly from the LLM's knowledge

The agent should use the LLM client and web scraper we created. Add logging so I can see what the agent is doing at each step.

IMPORTANT: The answer() method should accept a use_web_search parameter (defaults to True). 
If use_web_search is False, skip the web search decision logic entirely and go straight to answering from LLM knowledge.
Expected Output:

An agent.py file with an intelligent agent that orchestrates LLM reasoning and web search.

Prompt 7: API Server

> Goal: Expose the agent as a REST API

text
Create a FastAPI server in services/backend/main.py that:
- Has a POST /api/query endpoint that accepts a question and returns the agent's answer
- Has health check endpoints (GET / and GET /health)
- Loads the API keys from environment variables using the config.py settings
- Enables CORS so the frontend can call it

The request should be {"query": "...", "use_web_search": true} and response should be {"answer": "..."}.

IMPORTANT: Do NOT use the deprecated @app.on_event("startup") and @app.on_event("shutdown") decorators.
Instead, use the modern approach:
1. Import asynccontextmanager from contextlib
2. Create a lifespan async context manager function that handles startup and shutdown
3. Pass it to FastAPI as: app = FastAPI(lifespan=lifespan)

This prevents deprecation warnings.
Expected Output:

A main.py file with a FastAPI server exposing the agent.

Prompt 8: Frontend Setup

> Goal: Initialize the React frontend

text
Set up a React TypeScript frontend in services/frontend/ using Vite.

I'll need:
- React with TypeScript
- A markdown renderer (react-markdown with remark-gfm) to display formatted AI responses
- Environment variable support for the API URL

Create all the necessary config files (package.json, vite.config.ts, tsconfig.json, index.html) and the basic entry point files.
Expected Output:
  • package.json with React and markdown dependencies
  • Vite and TypeScript configuration files
  • index.html and src/main.tsx entry points
  • .env file with VITE_API_URL=http://localhost:8000

Prompt 9: User Interface

> Goal: Build the chat interface

text
Create the main React component in services/frontend/src/App.tsx.

I want a simple chat interface where users can:
- Type a question in an input field
- Click "Ask" (or press Enter) to submit
- See a loading spinner while waiting
- See the AI's answer rendered as markdown (with tables, lists, links, etc.)
- See their recent query history (last 5 questions)

Handle errors gracefully and show error messages to the user.
Expected Output:

An App.tsx file with a complete chat interface component.

Prompt 10: Styling

> Goal: Make it look good

text
Create modern, professional CSS styling for the frontend in services/frontend/src/App.css.

I want:
- A gradient background (dark blue to red tones)
- A clean white card in the center for the content
- Nice input field and button styling
- A spinning loader animation
- Good typography for the markdown content (headers, lists, tables, code blocks)
- Mobile responsive design

Make it look polished and professional.
Expected Output:

An App.css file with complete styling.

Prompt 11: Development Commands

> Goal: Create convenient commands for development

text
Create a Makefile in the project root with commands to:
- Install all dependencies (both backend and frontend)
- Run the backend server
- Run the frontend dev server
- Run both together

Make it easy to get started with just "make install" and "make dev".

IMPORTANT: Add command aliases so both of these work:
- make run-backend AND make dev-backend (both do the same thing)
- make run-frontend AND make dev-frontend (both do the same thing)

This ensures consistency with different naming conventions.
Expected Output:

A Makefile with install and dev commands for both services.

Prompt 12: Add Web Search Toggle

> Goal: Add user control over web search functionality

text
Add a "Web Search" checkbox to the frontend that allows users to control whether the AI agent uses BrightData for web search.

Frontend changes (services/frontend/src/App.tsx):
- Add a checkbox state (useWebSearch) that defaults to true
- Add a checkbox UI above the input field with a clear label and description
- Send the checkbox state (use_web_search) in the API request body
- Update the loading message to show different text based on whether web search is enabled

Backend changes (services/backend/main.py):
- Update the QueryRequest model to accept an optional use_web_search boolean (defaults to True)
- Pass this parameter to the agent

Backend changes (services/backend/agent.py):
- Update the run() method to accept a use_web_search parameter
- If use_web_search is False, skip all web search logic and answer directly with the LLM
- Add logging to show whether web search is enabled or disabled

This feature lets users compare answers with and without web search.
Expected Output:
  • Updated App.tsx with a "Web Search" checkbox
  • Updated main.py with the new request parameter
  • Updated agent.py with conditional web search logic

Verification Steps

After generating all the code, verify your project structure matches:

text
deep-research-agent/
β”œβ”€β”€ services/
β”‚   β”œβ”€β”€ backend/
β”‚   β”‚   β”œβ”€β”€ .env
β”‚   β”‚   β”œβ”€β”€ .env.example
β”‚   β”‚   β”œβ”€β”€ agent.py
β”‚   β”‚   β”œβ”€β”€ llm.py
β”‚   β”‚   β”œβ”€β”€ main.py
β”‚   β”‚   β”œβ”€β”€ requirements.txt
β”‚   β”‚   └── scraper.py
β”‚   └── frontend/
β”‚       β”œβ”€β”€ src/
β”‚       β”‚   β”œβ”€β”€ App.css
β”‚       β”‚   β”œβ”€β”€ App.tsx
β”‚       β”‚   β”œβ”€β”€ index.css
β”‚       β”‚   └── main.tsx
β”‚       β”œβ”€β”€ .env
β”‚       β”œβ”€β”€ index.html
β”‚       β”œβ”€β”€ package.json
β”‚       β”œβ”€β”€ tsconfig.json
β”‚       └── vite.config.ts
└── Makefile

Running the Project

Step 1: Configure Environment Variables

Edit services/backend/.env with your actual API keys:

env
BRIGHTDATA_API_TOKEN=your-actual-brightdata-token
ZEABUR_API_TOKEN=your-actual-zeabur-token
ZEABUR_MODEL=gpt-4o-mini
PORT=8000

Step 2: Install Dependencies

bash
# Install all dependencies
make install

# Or install separately:
cd services/backend && pip3 install -r requirements.txt
cd services/frontend && npm install

Step 3: Start the Backend

bash
make dev-backend
# Or: cd services/backend && python3 main.py

You should see:

text
βœ… Environment loaded successfully
πŸ”— Connecting to Zeabur AI Hub: https://sfo1.aihub.zeabur.ai
πŸ€– Using model: gpt-4o-mini
πŸš€ Web Search AI Agent Server running on http://localhost:8000

Step 4: Start the Frontend (new terminal)

bash
make dev-frontend
# Or: cd services/frontend && npm run dev

You should see:

text
VITE ready in XXX ms
➜  Local:   http://localhost:5173/

Step 5: Test the Application

  1. Open http://localhost:5173 in your browser
  2. You'll see a "Web Search" checkbox (checked by default)
  3. Type a question like "What are the latest developments in AI?"
  4. Click "Ask" and watch the magic happen!

Resources

  • Zeabur AI Hub: https://zeabur.com
  • BrightData: https://brightdata.com

Congratulations! πŸŽ‰

You've successfully vibe-coded a complete AI-powered research agent! This project demonstrates:

  • βœ… Python async programming with FastAPI
  • βœ… React frontend with TypeScript
  • βœ… OpenAI-compatible API integration
  • βœ… Web scraping with BrightData
  • βœ… AI Agent architecture (ReAct pattern)
  • βœ… RAG (Retrieval-Augmented Generation)
  • βœ… User-controlled feature toggles
  • βœ… Full-stack development with AI assistance

Next Steps

Want to extend your agent? Try these ideas:

  • Add source citations showing which websites were used
  • Implement streaming responses for real-time answers
  • Add conversation memory to maintain context across queries
  • Support multiple search engines (Google, Bing, DuckDuckGo)
  • Add user authentication and query history storage
  • Deploy to production (Zeabur, Vercel, Railway, etc.)
Share your creation and tag us @theaibuildersdev!

---

Technical Notes (For Instructors)

These prompts have been enhanced with specific technical details to ensure error-free implementation:

Built-in Fixes

  1. Prompt 3 - CORS validator using pydantic field_validator to parse comma-separated strings
  2. Prompt 5 - URL encoding with quote_plus, removed unsupported language parameter, BrightData response body extraction and JSON parsing
  3. Prompt 6 - use_web_search parameter for conditional search logic
  4. Prompt 7 - Modern FastAPI lifespan handler instead of deprecated on_event decorators
  5. Prompt 11 - Command aliases (dev-backend/run-backend, dev-frontend/run-frontend)
  6. Prompt 12 - Complete web search toggle implementation

Why These Fixes Matter

  • CORS Validator: Prevents SettingsError when loading environment variables
  • URL Encoding: Handles search queries with spaces and special characters
  • Response Parsing: Correctly extracts search results from BrightData's nested response structure
  • Lifespan Handler: Eliminates deprecation warnings in FastAPI 0.109+
  • Command Aliases: Supports both naming conventions for better UX

Verification

After students complete all prompts, they can verify everything works by running:

bash
make install
make dev-backend  # Terminal 1
make dev-frontend # Terminal 2

The app should start without errors and be fully functional at http://localhost:3000